package com.dataart.training.crimequalification.service;

import com.dataart.training.crimequalification.dao.UserDAO;
import com.dataart.training.crimequalification.entity.UserEntity;
import com.dataart.training.crimequalification.entity.UserRoleEntity;
import com.dataart.training.crimequalification.security.SimpleGrantedAuthority;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Transactional
@Service
public class UserServiceImpl implements UserService {

    // -------------------------------------------------------------

    @Autowired
    private UserDAO userDAO;

    // -------------------------------------------------------------

    /**
     * Returns list of all users present in the storage.
     *
     * @return list of all existing users
     */
    @Override
    public List<UserEntity> getAllUsers() {
        return userDAO.getAllUsers();
    }

    /**
     * Allows to look up user by a given id.
     *
     * @param id identification key to look up user with
     * @return user principal registered by id
     */
    @Override
    public UserEntity getUserById(Long id) {
        return userDAO.getUserById(id);
    }

    /**
     * Allows to find user with pair of given credentials.
     *
     * @param login    username to look up user by
     * @param password password to look up user by
     * @return user principal registered by these username and password
     */
    @Override
    public UserEntity getUserAuthorization(String login, String password) {
        return userDAO.getUserAuthorization(login, password);
    }

    /**
     * Allows to find user by a given username.
     *
     * @param username username to look up user by
     * @return user principal registered by the username
     */
    @Override
    public UserEntity getUserByUsername(String username) {
        return userDAO.getUserByUsername(username);
    }

    /**
     * Saves a given user principal in the storage.
     *
     * @param user user principal to be saved
     */
    @Override
    public void addNewUser(UserEntity user) {
        userDAO.addNewUser(user);
    }

    /**
     * Allows to find user by a given telephone number.
     *
     * @param phoneNumber telephone number to look up user by
     * @return user principal registered by the telephone number
     */
    @Override
    public UserEntity getUserByPhoneNumber(String phoneNumber) {
        return userDAO.getUserByPhoneNumber(phoneNumber);
    }

    /**
     * Updates user principal currently existing in the storage.
     *
     * @param user user principal to be updated
     */
    @Override
    public void updateUserDetails(UserEntity user) {
        userDAO.updateUserDetails(user);
    }

    /**
     * Grants given role to a user.
     *
     * @param user user to be assigned to role
     * @param role role to be granted
     */
    @Override
    public void assignRoleToUser(UserEntity user, String role) {
        userDAO.assignRoleToUser(user, role);
    }

    /**
     * Renders user principal verified.
     *
     * @param user user to be verified
     */
    @Override
    public void verifyUserAccount(UserEntity user) {
        userDAO.verifyUserAccount(user);
    }

    /**
     * Returns a user principal registered by the given e-mail address.
     *
     * @param email e-mail address to look up user by
     * @return user registered by a given e-mail
     */
    @Override
    public UserEntity getUserByEmail(String email) {
        return userDAO.getUserByEmail(email);
    }

    /**
     * Converts given UserEntity into Spring Security's credentials container
     * implementation of <code>UserDetails</code> assuming <code>credentialsNotExpired</code>,
     * <code>accountNotExpired</code> and <code>accountNotLocked</code> to <code>true</code>.
     *
     * @param userEntity user entity to convert to Spring Security credentials container
     * @return <code>User</code> with the details taken from <code>userEntity</code>
     */
    @Override
    public User userEntityToUserDetails(UserEntity userEntity) {

        Collection<GrantedAuthority> authorities = new ArrayList<>();
        List<UserRoleEntity> userRoles = userDAO.getUserRoles(userEntity);

        if (userRoles != null) {
            for (UserRoleEntity role : userRoles) {
                authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
            }
        }

        return new User(userEntity.getUsername(), userEntity.getPassword(),
                userEntity.getEnabled().equals(1), true, true, true, authorities);

    }

    /**
     * Removes given user from the persistent storage.
     * @param user user entity to remove
     */
    public void removeUser(UserEntity user) {
        userDAO.removeUser(user);
    }

}
